import typing
import ctypes
import psutil
import subprocess
import requests
import time
from selenium.webdriver.edge.webdriver import WebDriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
import rich


class BrowserController:
    """浏览器控制工具类，负责浏览器进程管理和驱动初始化"""
    
    @staticmethod
    def show_message(parent_hwnd: int = 0, title: str = '提示', text: str = '默认文本', msg_type: int = 0) -> int:
        """显示自定义消息框
        
        Args:
            parent_hwnd: 父窗口句柄
            title: 消息框标题
            text: 消息内容
            msg_type: 消息框类型
            
        Returns:
            int: 用户选择的按钮ID
        """
        return ctypes.windll.user32.MessageBoxW(parent_hwnd, text, title, msg_type)
    
    @staticmethod
    def is_process_running(process_name: str = "msedge.exe") -> bool:
        """检查是否存在指定名称的进程
        
        Args:
            process_name: 进程名称
            
        Returns:
            bool: 进程是否存在
        """
        for proc in psutil.process_iter(['name']):
            if proc.info['name'] == process_name:
                return True
        return False
    
    @staticmethod
    def is_debug_mode_active(local: str = "127.0.0.1", port: str = "9652") -> bool:
        """检查调试模式是否激活
        
        Args:
            local: 本地地址
            port: 端口号
            
        Returns:
            bool: 调试模式是否激活
        """
        url = f"http://{local}:{port}/json/version"
        try:
            response = requests.get(url=url, timeout=5)
            return response.status_code == 200
        except Exception as e:
            rich.print(f"[red]调试模式检查错误: {e}")
            return False
    
    @staticmethod
    def close_all_processes(process_name: str = "msedge.exe") -> bool:
        """关闭所有指定名称的进程
        
        Args:
            process_name: 进程名称
            
        Returns:
            bool: 是否成功关闭所有进程
        """
        success = True
        for proc in psutil.process_iter(['pid', 'name']):
            if process_name == proc.info['name']:
                try:
                    proc.kill()
                    rich.print(f"[green]已关闭进程 PID: {proc.info['pid']}")
                except Exception as e:
                    rich.print(f"[red]关闭进程 PID: {proc.info['pid']} 失败: {e}")
                    success = False
        return success
    
    @staticmethod
    def start_debug_mode_browser(
        local: str = "127.0.0.1",
        debug_port: int = 9652,
        user_data_dir: str = None,
        with_extensions: bool = False
    ) -> None:
        """启动带调试模式的浏览器
        
        Args:
            local: 本地地址
            debug_port: 调试端口
            user_data_dir: 用户数据目录
            with_extensions: 是否启用扩展
        """
        # 构建启动命令
        if user_data_dir:
            command = rf'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port={debug_port} --user-data-dir="{user_data_dir}" "http://{local}:{debug_port}/json/version"'
        else:
            command = rf'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port={debug_port} "http://{local}:{debug_port}/json/version"'
        
        # 启动新进程
        CREATE_NEW_CONSOLE = 0x00000010
        subprocess.Popen(command, shell=True, creationflags=CREATE_NEW_CONSOLE)
        rich.print(f"[green]已启动调试模式浏览器，端口: {debug_port}")
        time.sleep(3)  # 等待浏览器启动
    
    @staticmethod
    def create_driver_instance(
        local: str = "127.0.0.1", 
        port: int = 9652
    ) -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
        """创建WebDriver、WebDriverWait和ActionChains实例
        
        Args:
            local: 本地地址
            port: 端口号
            
        Returns:
            tuple: (driver, wait, actions) 三元组
        """
        options = Options()
        options.add_experimental_option("debuggerAddress", f"{local}:{port}")
        service = Service()
        driver = WebDriver(options=options, service=service)
        wait = WebDriverWait(driver=driver, timeout=10)
        actions = ActionChains(driver=driver)
        return driver, wait, actions
    
    @staticmethod
    def connect_debug_browser(
        local: str = "127.0.0.1",
        debug_port: int = 9652,
        user_data_dir: str = None
    ) -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
        """连接到调试模式浏览器，如未启动则自动启动
        
        Args:
            local: 本地地址
            debug_port: 调试端口
            user_data_dir: 用户数据目录
            
        Returns:
            tuple: (driver, wait, actions) 三元组
        """
        # 检查进程是否存在
        if not BrowserController.is_process_running():
            BrowserController.start_debug_mode_browser(
                local=local, 
                debug_port=debug_port, 
                user_data_dir=user_data_dir
            )
        else:
            # 检查调试模式是否激活
            if not BrowserController.is_debug_mode_active(local=local, port=str(debug_port)):
                if user_data_dir is not None:
                    BrowserController.start_debug_mode_browser(
                        local=local, 
                        debug_port=debug_port, 
                        user_data_dir=user_data_dir
                    )
                else:
                    # 询问用户是否关闭现有进程
                    result = BrowserController.show_message(
                        title="提示",
                        text="检测到浏览器进程但未启用调试模式，是否关闭所有浏览器进程?",
                        msg_type=4  # YES/NO 按钮
                    )
                    if result == 6:  # YES
                        BrowserController.close_all_processes()
                        BrowserController.start_debug_mode_browser(
                            local=local, 
                            debug_port=debug_port
                        )
                    else:  # NO
                        rich.print(f"[red]用户取消操作，程序退出")
                        exit(0)
        
        # 连接到调试浏览器
        return BrowserController.create_driver_instance(local=local, port=debug_port)
    
    @staticmethod
    def switch_to_active_tab(driver: WebDriver, local: str = "127.0.0.1", port: int = 9652) -> None:
        """切换到当前激活的标签页
        
        Args:
            driver: WebDriver实例
            local: 本地地址
            port: 端口号
        """
        try:
            debug_data = requests.get(f"http://{local}:{port}/json", timeout=5).json()
            if not isinstance(debug_data, list):
                rich.print(f"[red]调试接口返回数据格式不正确")
                return
                
            # 筛选有效的页面
            valid_pages = [
                page for page in debug_data 
                if page.get('type') == "page" and 
                not page.get('url', '').lower().startswith(("chrome-devtools", "chrome-extension"))
            ]
            
            if valid_pages:
                active_tab_id = valid_pages[0]['id']
                driver.switch_to.window(active_tab_id)
                rich.print(f"[green]已切换到激活标签页")
        except Exception as e:
            rich.print(f"[red]切换标签页失败: {e}")


def 强制启动浏览器(
    _local: str = "127.0.0.1",
    _debug_port: int = 9652,
    _user_data_dir: typing.Optional[str] = None
) -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
    """强制启动浏览器
    
    如果检测到当前进程中不存在调试模式的浏览器进程，直接强制启动新的调试模式浏览器
    
    Args:
        _local: 本地地址，默认127.0.0.1
        _debug_port: 调试端口，默认9652
        _user_data_dir: 用户数据目录，可选
        
    Returns:
        tuple: (driver, wait, actions) 三元组
        
    Example:
        driver, wait, actions = 强制启动浏览器()
    """
    # 检查调试模式是否激活
    _debug_mode_active = BrowserController.is_debug_mode_active(_local, str(_debug_port))
    
    if not _debug_mode_active:
        # 如果调试模式未激活，直接启动新的调试模式浏览器
        rich.print(f"[yellow]调试模式未激活，强制启动新的调试模式浏览器")
        BrowserController.start_debug_mode_browser(
            local=_local,
            debug_port=_debug_port,
            user_data_dir=_user_data_dir
        )
    else:
        rich.print(f"[green]调试模式已激活，直接连接")
    
    # 连接到浏览器
    _result_tuple = BrowserController.create_driver_instance(_local, _debug_port)
    return _result_tuple


def 检查启动(
    _local: str = "127.0.0.1",
    _debug_port: int = 9652,
    _user_data_dir: typing.Optional[str] = None
) -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
    """检查启动浏览器
    
    检测是否有调试模式的浏览器进程，如果有就使用，如果没有则询问用户是否关闭所有当前浏览器进程
    然后重新启动带有调试模式的浏览器
    
    Args:
        _local: 本地地址，默认127.0.0.1
        _debug_port: 调试端口，默认9652
        _user_data_dir: 用户数据目录，可选
        
    Returns:
        tuple: (driver, wait, actions) 三元组
        
    Example:
        driver, wait, actions = 检查启动()
    """
    # 检查调试模式是否激活
    _debug_mode_active = BrowserController.is_debug_mode_active(_local, str(_debug_port))
    
    if _debug_mode_active:
        rich.print(f"[green]调试模式已激活，直接连接")
    else:
        # 检查是否有浏览器进程
        _process_running = BrowserController.is_process_running()
        
        if _process_running:
            # 有浏览器进程但未启用调试模式，询问用户
            rich.print(f"[yellow]检测到浏览器进程但未启用调试模式")
            _user_choice = BrowserController.show_message(
                title="浏览器进程检测",
                text="检测到浏览器进程但未启用调试模式，是否关闭所有浏览器进程并重新启动调试模式？",
                msg_type=4  # YES/NO 按钮
            )
            
            if _user_choice == 6:  # YES
                # 关闭所有浏览器进程
                BrowserController.close_all_processes()
                # 启动新的调试模式浏览器
                BrowserController.start_debug_mode_browser(
                    local=_local,
                    debug_port=_debug_port,
                    user_data_dir=_user_data_dir
                )
            else:  # NO
                rich.print(f"[red]用户取消操作，程序退出")
                exit(0)
        else:
            # 没有浏览器进程，直接启动调试模式
            rich.print(f"[yellow]未检测到浏览器进程，启动调试模式浏览器")
            BrowserController.start_debug_mode_browser(
                local=_local,
                debug_port=_debug_port,
                user_data_dir=_user_data_dir
            )
    
    # 连接到浏览器
    _result_tuple = BrowserController.create_driver_instance(_local, _debug_port)
    return _result_tuple


if __name__ == "__main__":
    # 测试强制启动函数
    print("=== 测试强制启动浏览器 ===")
    driver1, wait1, actions1 = 强制启动浏览器()
    print(f"强制启动成功: {driver1.current_url}")
    
    # 测试检查启动函数
    print("\n=== 测试检查启动浏览器 ===")
    driver2, wait2, actions2 = 检查启动()
    print(f"检查启动成功: {driver2.current_url}")
    
    # 关闭浏览器
    driver1.quit()
    driver2.quit()